﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DataStructures
{
	/// <summary>
	/// Represents a node in a Tree structure, with a parent node and zero or more child nodes.
	/// </summary>
	public class ComplexTree<T> : IDisposable where T : ComplexTree<T>
	{
		private T _Parent;
		public virtual T Parent
		{
			get { return _Parent; }
			set
			{
				if (value == _Parent)
				{
					return;
				}

				if (_Parent != null)
				{
					_Parent.Children.Remove(this);
				}

				if (value != null && !value.Children.Contains(this))
				{
					value.Children.Add(this);
				}

				_Parent = value;
			}
		}
		public bool HasParent { get { return Parent != null; } }
		public bool HasChildren { get { return Children != null && Children.Count > 0; } }
		public virtual ComplexTree<T> Root { get { return (Parent == null) ? this : Parent.Root; } }
		public virtual ComplexTreeList<T> Children { get; private set; }
		public virtual TraversalType TraversalType { get; set; }

		public ComplexTree()
		{
			Parent = null;
			Children = new ComplexTreeList<T>(this);
		}

		public ComplexTree(T Parent)
		{
			this.Parent = Parent;
			Children = new ComplexTreeList<T>(this);
		}

		public ComplexTree(ComplexTreeList<T> Children)
		{
			Parent = null;
			this.Children = Children;
			Children.Parent = (T)this;
		}

		public ComplexTree(T Parent, ComplexTreeList<T> Children)
		{
			this.Parent = Parent;
			this.Children = Children;
			Children.Parent = (T)this;
		}

		/// <summary>
		/// Reports a depth of nesting in the tree, starting at 0 for the root.
		/// </summary>
		public virtual int Depth { get { return (Parent == null ? -1 : Parent.Depth) + 1; } }

		public override string ToString()
		{
			string Description = "Depth=" + Depth.ToString() + ", Children=" + Children.Count.ToString();
			if (this == Root)
			{
				Description += " (Root)";
			}
			return Description;
		}

		#region IDisposable
		public bool IsDisposed { get; set; }

		public virtual void Dispose()
		{
			//CheckDisposed();

			//// clean up contained objects (in Value property)
			//if (TraversalDirection == TraversalDirection.BottomUp)
			//{
			//    foreach (ComplexTree<T> node in Children)
			//    {
			//        node.Dispose();
			//    }
			//}

			//OnDisposing();

			//if (TraversalDirection == TraversalDirection.TopDown)
			//{
			//    foreach (ComplexTree<T> node in Children)
			//    {
			//        node.Dispose();
			//    }
			//}

			//// TODO: clean up the tree itself

			//IsDisposed = true;
		}

		public event EventHandler Disposing;

		protected void OnDisposing()
		{
			if (Disposing != null)
			{
				Disposing(this, EventArgs.Empty);
			}
		}

		protected void CheckDisposed()
		{
			if (IsDisposed)
			{
				throw new ObjectDisposedException(GetType().Name);
			}
		}

		#endregion
	}
}
